{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Tensor\n",
    "\n",
    "[![](https://gitee.com/mindspore/docs/raw/master/resource/_static/logo_source.png)](https://gitee.com/mindspore/docs/blob/master/docs/programming_guide/source_zh_cn/tensor.ipynb)&emsp;[![](https://gitee.com/mindspore/docs/raw/master/resource/_static/logo_notebook.png)](https://obs.dualstack.cn-north-4.myhuaweicloud.com/mindspore-website/notebook/master/programming_guide/mindspore_tensor.ipynb)&emsp;[![](https://gitee.com/mindspore/docs/raw/master/resource/_static/logo_modelarts.png)](https://authoring-modelarts-cnnorth4.huaweicloud.com/console/lab?share-url-b64=aHR0cHM6Ly9vYnMuZHVhbHN0YWNrLmNuLW5vcnRoLTQubXlodWF3ZWljbG91ZC5jb20vbWluZHNwb3JlLXdlYnNpdGUvbm90ZWJvb2svbW9kZWxhcnRzL3Byb2dyYW1taW5nX2d1aWRlL21pbmRzcG9yZV90ZW5zb3IuaXB5bmI=&imagename=MindSpore1.1.1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 概述\n",
    "\n",
    "张量（Tensor）是MindSpore网络运算中的基本数据结构。张量中的数据类型可参考[dtype](https://www.mindspore.cn/doc/programming_guide/zh-CN/master/dtype.html)。\n",
    "\n",
    "不同维度的张量分别表示不同的数据，0维张量表示标量，1维张量表示向量，2维张量表示矩阵，3维张量可以表示彩色图像的RGB三通道等等。\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 张量构造\n",
    "\n",
    "构造张量时，支持传入`Tensor`、`float`、`int`、`bool`、`tuple`、`list`和`NumPy.array`类型，其中`tuple`和`list`里只能存放`float`、`int`、`bool`类型数据。\n",
    "\n",
    "`Tensor`初始化时，可指定dtype。如果没有指定dtype，初始值`int`、`float`、`bool`分别生成数据类型为`mindspore.int32`、`mindspore.float32`、`mindspore.bool_`的0维Tensor，\n",
    "初始值`tuple`和`list`生成的1维`Tensor`数据类型与`tuple`和`list`里存放的数据类型相对应，如果包含多种不同类型的数据，则按照优先级：`bool` < `int` < `float`，选择相对优先级最高类型所对应的mindspore数据类型。\n",
    "如果初始值是`Tensor`，则生成的`Tensor`数据类型与其一致；如果初始值是`NumPy.array`，则生成的`Tensor`数据类型与之对应。\n",
    "\n",
    "代码样例如下："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-02-03T02:59:50.340750Z",
     "start_time": "2021-02-03T02:59:49.571048Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1 2]\n",
      " [3 4]] \n",
      "\n",
      " 1 \n",
      "\n",
      " 2 \n",
      "\n",
      " True \n",
      "\n",
      " [1 2 3] \n",
      "\n",
      " [4. 5. 6.] \n",
      "\n",
      " [4. 5. 6.]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "from mindspore import Tensor\n",
    "from mindspore import dtype as mstype\n",
    "\n",
    "x = Tensor(np.array([[1, 2], [3, 4]]), mstype.int32)\n",
    "y = Tensor(1.0, mstype.int32)\n",
    "z = Tensor(2, mstype.int32)\n",
    "m = Tensor(True, mstype.bool_)\n",
    "n = Tensor((1, 2, 3), mstype.int16)\n",
    "p = Tensor([4.0, 5.0, 6.0], mstype.float64)\n",
    "q = Tensor(p, mstype.float64)\n",
    "\n",
    "print(x, \"\\n\\n\", y, \"\\n\\n\", z, \"\\n\\n\", m, \"\\n\\n\", n, \"\\n\\n\", p, \"\\n\\n\", q)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 张量的运算、属性和方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 运算\n",
    "\n",
    "张量支持多种操作符运算，包括算术运算、逻辑运算等。以下是一些常用运算操作符：\n",
    "\n",
    "   * 算术运算：加（`+`）、减（`-`）、乘（`*`）、除（`/`）、取模（`%`）、幂次方（`**`）、整除（`//`）\n",
    "\n",
    "   * 逻辑运算：等于（`==`）、不等于（`!=`）、大于（`>`）、大于等于（`>=`）、小于（`<`）、小于等于（`<=`）\n",
    "\n",
    "代码样例如下：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-02-03T02:59:50.347520Z",
     "start_time": "2021-02-03T02:59:50.342826Z"
    }
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "add: [5. 7. 9.]\nsub: [-3. -3. -3.]\nmul: [ 4. 10. 18.]\ndiv: [4. 2.5 2. ]\nmod: [1. 2. 3.]\npow: [1. 4. 9.]\nfloordiv: [4. 2. 2.]\nequal: [False True False]\nnot equal: [ True False True]\ngreater than: [ True False False]\ngreater or equal: [ True True False]\nless than: [False False True]\nless or equal: [False True True]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "from mindspore import Tensor\n",
    "from mindspore import dtype as mstype\n",
    "\n",
    "x = Tensor(np.array([1, 2, 3]), mstype.float32)\n",
    "y = Tensor(np.array([4, 5, 6]), mstype.float32)\n",
    "output_add = x + y\n",
    "output_sub = x - y\n",
    "output_mul = x * y\n",
    "output_div = y / x\n",
    "output_mod = x % y\n",
    "output_pow = x ** 2\n",
    "output_floordiv = y // x\n",
    "print(\"add:\", output_add)\n",
    "print(\"sub:\", output_sub)\n",
    "print(\"mul:\", output_mul)\n",
    "print(\"div:\", output_div)\n",
    "print(\"mod:\", output_mod)\n",
    "print(\"pow:\", output_pow)\n",
    "print(\"floordiv:\", output_floordiv)\n",
    "\n",
    "a = Tensor(np.array([2, 2, 2]), mstype.int32)\n",
    "b = Tensor(np.array([1, 2, 3]), mstype.int32)\n",
    "output_eq = a == b\n",
    "output_ne = a != b\n",
    "output_gt = a > b\n",
    "output_gq = a >= b\n",
    "output_lt = a < b\n",
    "output_lq = a <= b\n",
    "print(\"equal:\", output_eq)\n",
    "print(\"not equal:\", output_ne)\n",
    "print(\"greater than:\", output_gt)\n",
    "print(\"greater or equal:\", output_gq)\n",
    "print(\"less than:\", output_lt)\n",
    "print(\"less or equal:\", output_lq)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 属性\n",
    "\n",
    "张量的属性包括形状（shape）、数据类型（dtype）、转置张量（T）、单个元素大小（itemsize）、占用字节数量（nbytes）、维数（ndim）、元素个数（size）、每一维步长（strides）。\n",
    "\n",
    "   * 形状：`Tensor`的shape，是一个tuple。\n",
    "\n",
    "   * 数据类型：`Tensor`的dtype，是MindSpore的一个数据类型。\n",
    "\n",
    "   * 转置张量：`Tensor`的转置，也是一个`Tensor`。\n",
    "\n",
    "   * 单个元素大小： `Tensor`中每一个元素占用字节数，是一个整数。\n",
    "\n",
    "   * 占用字节数量： `Tensor`占用的总字节数，是一个整数。\n",
    "\n",
    "   * 维数： `Tensor`的秩，也就是len(tensor.shape)，是一个整数。\n",
    "\n",
    "   * 元素个数： `Tensor`中所有元素的个数，是一个整数。\n",
    "\n",
    "   * 每一维步长： `Tensor`中每一维中进行遍历所需要经过的字节数。\n",
    "\n",
    "代码样例如下："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-02-03T02:59:50.347520Z",
     "start_time": "2021-02-03T02:59:50.342826Z"
    }
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "x_shape: (2, 2)\nx_dtype: Int32\nx_transposed: [[1 3]\n [2 4]]\nx_itemsize: 4\nx_nbytes: 16\nx_ndim: 2\nx_size: 4\nx_strides: (8, 4)\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "from mindspore import Tensor\n",
    "from mindspore import dtype as mstype\n",
    "\n",
    "x = Tensor(np.array([[1, 2], [3, 4]]), mstype.int32)\n",
    "x_shape = x.shape\n",
    "x_dtype = x.dtype\n",
    "x_transposed = x.T\n",
    "x_itemsize = x.itemsize\n",
    "x_nbytes = x.nbytes\n",
    "x_ndim = x.ndim\n",
    "x_size = x.size\n",
    "x_strides = x.strides\n",
    "print(\"x_shape:\", x_shape)\n",
    "print(\"x_dtype:\", x_dtype)\n",
    "print(\"x_transposed:\", x_transposed)\n",
    "print(\"x_itemsize:\", x_itemsize)\n",
    "print(\"x_nbytes:\", x_nbytes)\n",
    "print(\"x_ndim:\", x_ndim)\n",
    "print(\"x_size:\", x_size)\n",
    "print(\"x_strides:\", x_strides)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 方法\n",
    "\n",
    "张量的方法包括`len`、`str`、`repr`、`hash`、`all`、`any`和`asnumpy`等，我们同时提供了与`Numpy`的`ndarray`使用方式类似的Tensor方法来提升用户体验。详细的方法列表，使用方式以及支持后端请参考[Tensor类方法API](https://www.mindspore.cn/doc/api_python/zh-CN/master/mindspore/mindspore.html#mindspore.Tensor)，以下是一些类方法的简单介绍：\n",
    "\n",
    "- `len()`：返回张量的长度。\n",
    "\n",
    "- `str()`：返回张量的字符串表达。\n",
    "\n",
    "- `repr()`：返回张量的字符串表达，供解释器读取。\n",
    "\n",
    "- `hash()`：获取张量的哈希值。\n",
    "\n",
    "- `all(axis, keep_dims)`：在指定维度上通过`and`操作进行归约，`axis`代表归约维度，`keep_dims`表示是否保留归约后的维度。\n",
    "\n",
    "- `any(axis, keep_dims)`：在指定维度上通过`or`操作进行归约，参数含义同`all`。\n",
    "\n",
    "- `asnumpy()`：将`Tensor`转换为`NumPy`的`array`。\n",
    "\n",
    "- `sum(axis, dtype, keepdims, initial)`: 在指定维度上对张量进行归约求和，`axis`代表归约维度，`dtype`代表输出的数据的类型，`keepdims`表示是否保留归约后的维度, `initial`表示规约求和开始前的初始值。\n",
    "\n",
    "代码样例如下："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-02-03T02:59:50.374128Z",
     "start_time": "2021-02-03T02:59:50.349665Z"
    }
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "t_len: 3\nt_str: [1 2 3]\nt_repr: Tensor(shape=[3], dtype=Int32, value= [1, 2, 3])\nt_hash: 281470264268272\nx_all: False\nx_any: True\nx_array: [[ True  True]\n [False False]]\ny_sum_tensor: 10.0\ny_sum_mnp: 10.0\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "from mindspore import Tensor\n",
    "from mindspore import dtype as mstype\n",
    "\n",
    "t = Tensor(np.array([1, 2, 3]), mstype.int32)\n",
    "t_len = len(t)\n",
    "t_str = str(t)\n",
    "t_repr = repr(t)\n",
    "t_hash = hash(t)\n",
    "print(\"t_len:\", t_len)\n",
    "print(\"t_str:\", t_str)\n",
    "print(\"t_repr:\", t_repr)\n",
    "print(\"t_hash:\", t_hash)\n",
    "\n",
    "x = Tensor(np.array([[True, True], [False, False]]), mstype.bool_)\n",
    "x_all = x.all()\n",
    "x_any = x.any()\n",
    "x_array = x.asnumpy()\n",
    "print(\"x_all:\", x_all)\n",
    "print(\"x_any:\", x_any)\n",
    "print(\"x_array:\", x_array)\n",
    "\n",
    "import mindspore.numpy as mnp\n",
    "y = Tensor(np.array([[1., 2.], [3., 4.]]), mstype.float32)\n",
    "# y.sum() and mindspore.numpy.sum(y) are equivalent methods\n",
    "y_sum_tensor = y.sum()\n",
    "y_sum_mnp = mnp.sum(y)\n",
    "print(\"y_sum_tensor:\", y_sum_tensor)\n",
    "print(\"y_sum_mnp:\", y_sum_mnp)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 稀疏张量\n",
    "\n",
    "稀疏张量是一种特殊张量，其中绝大部分元素的值为零。在某些应用场景中（比如推荐系统），数据的特征是稀疏的，若使用普通张量表征这些数据会引入大量不必要的计算，存储和通讯开销。在这种时候就可以使用稀疏张量来表征这些数据。\n",
    "\n",
    "常用稀疏张量的表达形式是`<indices:Tensor, values:Tensor, dense_shape:Tensor>`。其中，`indices`表示非零下标元素， `values`表示非零元素的值，dense_shape表示的是被压缩的稀疏张量的形状。 在这个结构下，我们定义了`RowTensor`和`SparseTensor`两种稀疏张量结构。\n",
    "\n",
    "> PyNative模式暂不支持稀疏张量。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### RowTensor\n",
    "`RowTensor`用于压缩第零个维度稀疏的张量。若`RowTensor`的维度为`[L0, D1, D2, ..., DN ]`。第零维度的非零元素个数为`D0`, 则有`L0 >> D0`。\n",
    "- `indices`: 一维整数张量，表示稀疏张量第零维度中非零元素的位置。形状：`[D0]`\n",
    "- `values`: 表示相对应的非零元素的值。形状：`[D0, D1, D2, ..., DN]`\n",
    "- `dense_shape`: 表示的是被压缩的稀疏张量的形状。\n",
    "\n",
    "代码样例如下："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "[[1. 2.]]\n",
      "[0]\n",
      "(3, 2)"
     ]
    }
   ],
   "source": [
    "import mindspore as ms\n",
    "import mindspore.nn as nn\n",
    "from mindspore import RowTensor\n",
    "class Net(nn.Cell):\n",
    "    def __init__(self, dense_shape):\n",
    "        super(Net, self).__init__()\n",
    "        self.dense_shape = dense_shape\n",
    "    def construct(self, indices, values):\n",
    "        x = RowTensor(indices, values, self.dense_shape)\n",
    "        return x.values, x.indices, x.dense_shape\n",
    "    \n",
    "indices = Tensor([0])\n",
    "values = Tensor([[1, 2]], dtype=ms.float32)\n",
    "out = Net((3, 2))(indices, values)\n",
    "print(out[0])\n",
    "print(out[1])\n",
    "print(out[2])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### SparseTensor\n",
    "`SparseTensor`用于压缩非零元素位置分布不规则的Tensor，若非零元素的个数为`N`，被压缩的张量的维数为`ndims`，则有：\n",
    "- `indices`: 二维整数张量，每行代表非零元素下标。形状：`[N, ndims]`\n",
    "- `values`: 一维张量，表示相对应的非零元素的值。形状：`[N]`\n",
    "- `dense_shape`: 表示的是被压缩的稀疏张量的形状。\n",
    "\n",
    "代码样例如下："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
         "output_type": "stream",
         "name": "stdout",
         "text": [
          "[1. 2.]\n",
          "[[0 1]\n",
          " [1 2]]\n",
          "(3, 4)"
         ]
    }
   ],
   "source": [
    "import mindspore as ms\n",
    "import mindspore.nn as nn\n",
    "from mindspore import SparseTensor\n",
    "class Net(nn.Cell):\n",
    "    def __init__(self, dense_shape):\n",
    "       super(Net, self).__init__()\n",
    "       self.dense_shape = dense_shape\n",
    "    def construct(self, indices, values):\n",
    "       x = SparseTensor(indices, values, self.dense_shape)\n",
    "       return x.values, x.indices, x.dense_shape\n",
    "\n",
    "indices = Tensor([[0, 1], [1, 2]])\n",
    "values = Tensor([1, 2], dtype=ms.float32)\n",
    "out = Net((3, 4))(indices, values)\n",
    "print(out[0])\n",
    "print(out[1])\n",
    "print(out[2])"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "name": "python3",
   "display_name": "Python 3.7.5 64-bit ('ms_cpu': conda)",
   "metadata": {
    "interpreter": {
     "hash": "875445de5dd7c586490cddad65077f7a4acd26e265832f538fdbbee59bc2bd79"
    }
   }
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.5-final"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}

